package com.dlc.beijingrfid.net.protocol.base;

import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import com.dlc.commonlibrary.utils.LogPlus;
import com.dlc.commonlibrary.utils.ResUtil;
import com.dlc.beijingrfid.R;
import com.dlc.beijingrfid.helper.UserHelper;
import com.dlc.beijingrfid.net.NetConstants;
import com.dlc.beijingrfid.net.exception.ErrorMsgException;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.lzy.okgo.OkGo;
import com.lzy.okgo.convert.StringConvert;
import com.lzy.okgo.model.HttpHeaders;
import com.lzy.okgo.model.HttpParams;
import java.io.IOException;
import java.text.SimpleDateFormat;
import okhttp3.Response;
import org.json.JSONObject;
import rx.Observable;
import rx.Subscriber;
import rx.android.schedulers.AndroidSchedulers;
import rx.schedulers.Schedulers;

/**
 * Created by John on 2017/6/12.
 */

public class HttpProtocol {

    public static final SimpleDateFormat API_DATE = new SimpleDateFormat("yyyy-MM-dd");
    public static final Gson GSON = new GsonBuilder().serializeNulls().create();
    private static final StringConvert CONVERT = new StringConvert();

    public interface Callback<T> {

        void onSuccess(T t);

        void onFailed(int code, ErrorMsgException e);
    }

    public interface SimpleCallback {
        void onResult(int code);
    }

    /**
     * 同步请求
     *
     * @param url
     * @param headers
     * @param params
     * @return
     * @throws IOException
     */
    private Response syncPost(String url, HttpHeaders headers, HttpParams params)
        throws IOException {
        Response response = OkGo.post(url).headers(headers).params(params).execute();
        return response;
    }

    /**
     * 同步请求返回文本
     *
     * @param url
     * @param headers
     * @param params
     * @return
     * @throws Throwable
     */
    private String syncPostText(String url, HttpHeaders headers, HttpParams params)
        throws Throwable {
        Response response = OkGo.post(url).headers(headers).params(params).execute();
        String string = CONVERT.convertResponse(response);
        response.close();
        return string;
    }

    /**
     * 同步请求返回bean
     *
     * @param url
     * @param headers
     * @param params
     * @param clazz
     * @param <T>
     * @return
     * @throws Throwable
     */
    private <T> T syncPostBean(String url, HttpHeaders headers, HttpParams params, Class<T> clazz)
        throws Throwable {

        Response response = syncPost(url, headers, params);
        String text = CONVERT.convertResponse(response);

        LogPlus.w("response=" + text);

        response.close();

        T bean = GSON.fromJson(text, clazz);
        return bean;
    }

    /**
     * rx请求
     *
     * @param url
     * @param headers
     * @param params
     * @param clazz
     * @param errorString
     * @param <T>
     * @return
     */
    private <T> Observable<T> rxPost(final String url, final HttpHeaders headers,
        @Nullable final HttpParams params, final Class<T> clazz, final String errorString) {

        return Observable.unsafeCreate(new Observable.OnSubscribe<T>() {
            @Override
            public void call(Subscriber<? super T> subscriber) {

                try {

                    String text = syncPostText(url, headers, params);

                    LogPlus.e("response=" + text);

                    JSONObject jsonObject = new JSONObject(text);
                    int code = jsonObject.getInt("code");
                    String msg = jsonObject.getString("msg");

                    LogPlus.w("code=" + code + ",msg=" + msg);

                    if (code == 1) {
                        T result = GSON.fromJson(text, clazz);
                        subscriber.onNext(result);
                        subscriber.onCompleted();
                    } else {
                        String error = TextUtils.isEmpty(errorString) ? msg : errorString;
                        error = TextUtils.isEmpty(error) ? ResUtil.getString(R.string.net_error)
                            : error;
                        subscriber.onError(new ErrorMsgException(error, code));
                    }
                } catch (Throwable throwable) {
                    throwable.printStackTrace();
                    subscriber.onError(
                        new ErrorMsgException(R.string.net_error, NetConstants.CODE_NET_ERROR));
                }
            }
        });
    }

    /**
     * 获取请求URL
     *
     * @param api api
     * @param auth 需要认证
     * @return
     */
    protected String getRequestUrl(@NonNull String api, boolean auth) {
        if (auth) {
            //userid={{userid}}&timestamp={{timestamp}}&sign={{sign}}
            StringBuilder sb = new StringBuilder(NetConstants.BASE_URL);
            sb.append(api)
                .append("?")
                .append("userid=")
                .append(UserHelper.get().getId())
                .append("&timestamp=")
                .append(UserHelper.get().getTimestamp())
                .append("&sign=")
                .append(UserHelper.get().getSign());
            return sb.toString();
        } else {
            return NetConstants.BASE_URL + api;
        }
    }

    /**
     * rxjava方式的请求
     *
     * @param api
     * @param params
     * @param clazz
     * @param auth 是否需要授权
     * @param errorString
     * @param <T>
     * @return
     */
    public <T> Observable<T> rxPost(String api, @Nullable final HttpParams params,
        final Class<T> clazz, boolean auth, @Nullable final String errorString) {

        return rxPost(getRequestUrl(api, auth), null, params, clazz, errorString);
    }

    /**
     * 回调方式请求
     *
     * @param api
     * @param params
     * @param clazz
     * @param auth 是否需要授权
     * @param callback
     * @param <T>
     */
    public <T> void post(String api, @Nullable final HttpParams params, final Class<T> clazz,
        boolean auth, @NonNull final Callback<T> callback) {

        rxPost(api, params, clazz, auth, null).subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(new Subscriber<T>() {
                @Override
                public void onCompleted() {

                }

                @Override
                public void onError(Throwable tr) {
                    ErrorMsgException e = (ErrorMsgException) tr;
                    callback.onFailed(e.getCode(), e);
                }

                @Override
                public void onNext(T t) {
                    callback.onSuccess(t);
                }
            });
    }

    /**
     * rxjava方式的简单请求，只会返回 code
     *
     * @param api
     * @param params
     * @param auth 是否需要授权
     * @return
     */
    public Observable<Integer> rxSimplePost(final String api, @Nullable final HttpParams params,
        final boolean auth) {
        return Observable.unsafeCreate(new Observable.OnSubscribe<Integer>() {
            @Override
            public void call(Subscriber<? super Integer> subscriber) {

                try {
                    String text = syncPostText(getRequestUrl(api, auth), null, params);

                    LogPlus.w("response=" + text);

                    JSONObject jsonObject = new JSONObject(text);
                    int code = jsonObject.getInt("code");
                    String msg = jsonObject.getString("msg");

                    LogPlus.w("code=" + code + ",msg=" + msg);

                    subscriber.onNext(code);
                } catch (Throwable throwable) {
                    throwable.printStackTrace();
                    subscriber.onNext(NetConstants.CODE_NET_ERROR);
                }
                subscriber.onCompleted();
            }
        });
    }

    /**
     * 回调方式的简单请求，只会返回 code
     *
     * @param api
     * @param params
     * @param auth 授权
     * @param simpleCallback
     */
    public void simplePost(final String api, @Nullable final HttpParams params, boolean auth,
        final SimpleCallback simpleCallback) {
        rxSimplePost(api, params, auth).subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(new Subscriber<Integer>() {
                @Override
                public void onCompleted() {

                }

                @Override
                public void onError(Throwable e) {

                }

                @Override
                public void onNext(Integer integer) {
                    if (simpleCallback != null) {
                        simpleCallback.onResult(integer);
                    }
                }
            });
    }
}
